#region File Header
//----------------------------------------------------------------
// Copyright (C) 2003 Stefan Kyntchev
// All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT 
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR 
// FITNESS FOR A PARTICULAR PURPOSE.
//----------------------------------------------------------------
#endregion File Header

using System;
using System.Web;
using System.IO;

namespace FlashBack.Web
{
	/// <summary>
	/// This class renders a progress bar on the client and controls
	/// the progress from the server side
	/// This is accomplished by sending data back to the client at
	/// predetermined intervals of time. In order for this to work
	/// page buffering needs to be disabled
	/// </summary>
	public class ServerProgressBar
	{
		#region Data Members
		int m_minValue = 0;
		int m_maxValue = 100;
		int m_stepValue = 10;
		int m_barSize = 40;
		int m_pageBarID = 0;
		string m_elementID = "progBarHolder";
		string m_barColor = "blue"; 
		string m_outerHTML = string.Empty;
		
		static string m_scriptEngineLocation = "ProgressBar.js";
		string m_clientJavaScript = string.Empty;
		#endregion

		#region Constructors
		/// <summary>
		/// Builds a generic progress bar with default outer HTML (simple table),
		/// color and size
		/// </summary>
		public ServerProgressBar()
		{
			//This will generate a unique progress bar ID for
			//each bar that is on the same page
			//(if for some wired reason more than one bars are needed)
			if(!HttpContext.Current.Items.Contains("PageBarID"))
			{
				HttpContext.Current.Items["PageBarID"] = 0;
			}

			m_pageBarID = 1 + (int)HttpContext.Current.Items["PageBarID"];
			HttpContext.Current.Items["PageBarID"] = m_pageBarID;
		}
		
		/// <summary>
		/// Builds a bar with particular size and outerHTML
		/// </summary>
		/// <param name="i_barSize">Size of the bar in "tick marks"</param>
		/// <param name="i_barColor">Color of the tick mark</param>
		/// <param name="i_outerHTML">HTML surrounding the bar. (see OuterHTML property)</param>
		/// <param name="i_hostElementID">ID of an element in the OuterHTML that will
		/// host the bar</param>
		public ServerProgressBar(int i_barSize, string i_barColor,
									string i_outerHTML, string i_hostElementID):this()
		{
			BarSize = i_barSize;
			BarColor = i_barColor;
			OuterHTML = i_outerHTML;
			HostElementID = i_hostElementID;
		}

		/// <summary>
		/// Builds a bar with all parameters
		/// </summary>
		/// <param name="i_minValue">Minimum Value</param>
		/// <param name="i_maxValue">Maximum Value</param>
		/// <param name="i_stepValue">Step Value (see StepValue property)</param>
		/// <param name="i_barSize">Size of the bar in "tick marks"</param>
		/// <param name="i_barColor">Color of the tick mark</param>
		/// <param name="i_outerHTML">HTML surrounding the bar. (see OuterHTML property)</param>
		/// <param name="i_hostElementID">ID of an element in the OuterHTML that will
		/// host the bar</param>
		public ServerProgressBar(int i_minValue, int i_maxValue, int i_stepValue,
								 int i_barSize, string i_barColor,
								 string i_outerHTML, string i_hostElementID):
			this(i_barSize, i_barColor, i_outerHTML,i_hostElementID)
		{
			MinValue = i_minValue;
			MaxValue = i_maxValue;
			StepValue = i_stepValue;
		}
		#endregion

		#region Public Properties
		/// <summary>
		/// This is the HTML that will surround the progress bar
		/// the progress bar will be rendered inside an element
		/// (usually a DIV) with a well known ID. Do not include the
		/// <html> tag because it will be automatically provided
		/// </summary>
		public string OuterHTML
		{
			get { return m_outerHTML; }
			set 
			{
				//If this is an empty string - just use some default value
				if(value == string.Empty)
				{
					m_outerHTML = "<table align='center'><tr><td id='progBarHolder'></td></tr></table>";
					return;
				}

				//If it starts with "file:" try to load it. 
				//this file should be in a virtual directory somewhere
				if(value.IndexOf("file:") != -1)
				{
					try
					{
						m_outerHTML = GetFromFile(value.Substring(5));
					}
					catch
					{
						m_outerHTML = "";
					}

					return;
				}

				//Just set it to whatever inline string was provided
				m_outerHTML = value;
			}
		}

		
		/// <summary>
		/// This is the path where the progress bar script engine (a JS file)
		/// is located. This file conatins the client side JavaScript used to
		/// render the progress bar
		/// The default value is in the same virtual path as the page using it
		/// </summary>
		public string ScriptEnginePath
		{
			get { return m_scriptEngineLocation; }
			set { m_scriptEngineLocation = value; }
		}


		/// <summary>
		/// The minimum value that the progress bar represents
		/// </summary>
		public int MinValue
		{
			get{ return m_minValue; }
			set{ m_minValue = value; }
		}

		/// <summary>
		/// The maximum value that the progress bar represents
		/// </summary>
		public int MaxValue
		{
			get{ return m_maxValue; }
			set{ m_maxValue = value; }
		}

		/// <summary>
		/// The step increment between the minimum and maximum values
		/// The progress bar represents a percent between the minimum
		/// and maximum value. Minimum value is 0% maximum is 100%. 
		/// Step value determines how many steps it takes to get from the
		/// minimum to the maximum value. For example if your range is 0-100
		/// and the step is 10 it will take 10 steps. If the step is 20 it
		/// will take 5. The step method will move the progress bar with
		/// 1 step 
		/// </summary>
		public int StepValue
		{
			get{ return m_stepValue; }
			set{ m_stepValue = value; }
		}

		/// <summary>
		/// This is the ID of an element in OuterHTML that will conatin
		/// the progress bar
		/// </summary>
		public string HostElementID
		{
			get{ return m_elementID; }
			set{ m_elementID = value; }
		}
		
		/// <summary>
		/// This is the color of the tick symbol of the bar. 
		/// This color is sent back to the client side so can be
		/// any named HTML color or an #RGB color
		/// </summary>
		public string BarColor
		{
			get{ return m_barColor; }
			set{ m_barColor = value; }
		}
		
		/// <summary>
		/// How many tick symbols does the bar contain. This is a good
		/// way to determine the overall size of the bar
		/// </summary>
		public int BarSize
		{
			get{ return m_barSize; }
			set{ m_barSize = value; }
		}

		#endregion

		#region Public Methods
		/// <summary>
		/// Renders all client scripts to the client
		/// </summary>
		public void RenderClientScript()
		{
			if(m_pageBarID == 1) // This is the first bar
			{
				//Send the Bar Engine script
				HttpContext.Current.Response.BufferOutput = false;
				HttpContext.Current.Response.Write("<html><div id='ProgressBarOutputArea'>");
				HttpContext.Current.Response.Write(BarScriptEngine);
				HttpContext.Current.Response.Write(OuterHTML);
				HttpContext.Current.Response.Write("</div>");
			}

			string buildScript = string.Format("<script language='JavaScript'>server_progress_bar{6} = new ProgressBar({0},{1},{2},{3},'{4}','{5}',{6});</script>",
				MinValue,MaxValue,StepValue,BarSize,HostElementID,BarColor,m_pageBarID);

			 HttpContext.Current.Response.Write(buildScript);
		}

		/// <summary>
		/// Sets the client indicator to show the supplied percent
		/// </summary>
		/// <param name="i_percent">Number between 0 and 100</param>
		public void SetPercent(int i_percent)
		{
			if(i_percent < 0 || i_percent > 100)
				throw new ArgumentException("Please provide a number between 0 and 100");

			HttpContext.Current.Response.Write(string.Format(
					"\n<script language='JavaScript'>server_progress_bar{1}.SetPercent({0})</script>",i_percent,m_pageBarID));
		}

		/// <summary>
		/// Makes the client progress bar increase by one step
		/// as defined in the constructor
		/// </summary>
		public void Step()
		{
			HttpContext.Current.Response.Write(string.Format(
				"\n<script language='JavaScript'>server_progress_bar{0}.Step()</script>",m_pageBarID));
		}
	
		/// <summary>
		/// Renders a script that instruct the client to redirect to a
		/// different page
		/// </summary>
		/// <param name="i_Url"></param>
		public void SendFinalRedirect(string i_Url)
		{
			HttpContext.Current.Response.Write(
				string.Format("\n<script language='JavaScript'>document.location.href = '{0}'</script>",i_Url));
		}

		/// <summary>
		/// Ereases the client side JavaScript used to render the progress Bar
		/// </summary>
		public void CleanProgressBar()
		{
			HttpContext.Current.Response.Write(
				string.Format("\n<script language='JavaScript'>var oa = document.getElementById('ProgressBarOutputArea'); if(oa != null) oa.parentNode.innerHTML = '';</script>"));
			HttpContext.Current.Response.BufferOutput = true;
		}

		#endregion

		#region Internal Implementation
		/// <summary>
		/// Returns the client side JavaScript used to display and
		/// manipilate the progress bar
		/// </summary>
		string BarScriptEngine
		{
			get 
			{
				if(m_clientJavaScript == string.Empty)
				{
					string output;
					try
					{
						output = GetFromFile(ScriptEnginePath);
					}
					catch
					{
						output = "alert('Unable to find JavaScript needed to generate the progress bar!')";
					}

					m_clientJavaScript = "<script language='javascript'>" + output + "</script>\n";
				}
				
				return m_clientJavaScript;
			}
		}

		/// <summary>
		/// Reads the conetent of a file into a memory string
		/// </summary>
		/// <param name="i_filename">virtyal path to the file to read</param>
		/// <returns>content of the file</returns>
		string GetFromFile(string i_filename)
		{
			string output;
			string p = HttpContext.Current.Server.MapPath(i_filename);
			StreamReader content = File.OpenText(p);
			output = content.ReadToEnd();
			content.Close();
			return output;
		}

		#endregion
	}
}
